using System;
using System.Collections.Generic;
using System.ComponentModel;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

using Elephant.Utility;

using Elephant.Framework;
using Elephant.Framework.Services;

namespace Elephant.Utility.Components
{
    [ComponentDependency(typeof(Transform))]
    public class Camera : Drawable
    {
        Transform transform;

        CullMode culling = CullMode.None;
        Color clearColor = Color.CornflowerBlue;

        float near = 0.1f;
        float far = 1000.0f;
        float fieldOfView = (float)MathHelper.PiOver4;
        float aspectRatio;

        GraphicsDevice device;

        public override void Initialize(bool addDependencies)
        {
            base.Initialize(addDependencies);

            // sucks to have to do this, but we're out of "working" alternatives
            // one could pass it through the constructor, but that would not work if this component was tagged as a dependency (no way of knowing parameters)
            device = GameHelper.GetService<IGraphicsDeviceService>().GraphicsDevice;

            // ffs what is wrong with this, casts or not?
            aspectRatio = (float)device.Viewport.Width / (float)device.Viewport.Height;

            transform = Owner.Find<Transform>();
        }

        public override void Start()
        {
            // since the camera is doing the viewport clearing, it is preferred to have it as the first in the drawables list.
            // This can obviously be changed, and wont guarantee that it'll be the first in the list. Even if it isn't the first
            // you will probably not notice any problems, but, as stated previously, it is good practice clearing as the first thing.
            DrawOrder = -1;
        }

        public override void Draw(GameTime gameTime)
        {
            device.Clear(clearColor);
        }

        public Color ClearColor
        {
            get
            {
                return clearColor;
            }
            set
            {
                clearColor = value;
            }
        }

        public CullMode Culling
        {
            get
            {
                return culling;
            }
            set
            {
                culling = value;
            }
        }

        public float Near
        {
            get
            {
                return near;
            }
            set
            {
                near = value;
            }
        }

        public float Far
        {
            get
            {
                return far;
            }
            set
            {
                far = value;
            }
        }

        public float FieldOfView
        {
            get
            {
                return fieldOfView;
            }
            set
            {
                fieldOfView = value;
            }
        }

        public float AspectRatio
        {
            get
            {
                return aspectRatio;
            }
        }

        public virtual Matrix Projection
        {
            get
            {
                return Matrix.CreatePerspectiveFieldOfView(
                    fieldOfView, 
                    aspectRatio, 
                    near, 
                    far);
            }
        }

        public virtual Matrix View
        {
            get
            {
                return Matrix.CreateLookAt(
                    transform.Position, 
                    Vector3.Zero, 
                    Vector3.Up);
            }
        }
    }
}
